﻿using EMall.Query;
using IdentityServer4.Models;
using IdentityServer4.Stores;
using Microsoft.EntityFrameworkCore;

namespace EMall.AuthServer
{
    public class IdentityServerResourceStore : IResourceStore
    {
        private readonly IQueryService _queryService;
        public IdentityServerResourceStore(IQueryService queryService)
        {
            _queryService = queryService;
        }
        public async Task<IEnumerable<ApiResource>> FindApiResourcesByNameAsync(IEnumerable<string> apiResourceNames)
        {
            var entities = await _queryService.GetQueryable<IdentityServer4.EntityFramework.Entities.ApiResource>()
                .Include(x => x.Secrets)
                .Include(x => x.Scopes)
                .Include(x => x.UserClaims)
                .Include(x => x.Properties)
                .AsNoTracking()
                .Where(o => apiResourceNames.Contains(o.Name))
                .ToListAsync();
            return entities.Select(o => o.ToModel());
        }
        public async Task<IEnumerable<ApiResource>> FindApiResourcesByScopeNameAsync(IEnumerable<string> scopeNames)
        {
            var entities = await _queryService.GetQueryable<IdentityServer4.EntityFramework.Entities.ApiResource>()
                .Include(x => x.Secrets)
                .Include(x => x.Scopes)
                .Include(x => x.UserClaims)
                .Include(x => x.Properties)
                .AsNoTracking()
                .ToListAsync();
            entities = entities.FindAll(o => scopeNames.Intersect(o.Scopes.Select(s => s.Scope)).Any());
            return entities.Select(o => o.ToModel());
        }
        public async Task<IEnumerable<ApiScope>> FindApiScopesByNameAsync(IEnumerable<string> scopeNames)
        {
            var entities = await _queryService.GetQueryable<IdentityServer4.EntityFramework.Entities.ApiScope>()
                .Include(x => x.UserClaims)
                .Include(x => x.Properties)
                .AsNoTracking()
                .Where(o => scopeNames.Contains(o.Name))
                .ToListAsync();
            return entities.Select(o => o.ToModel());
        }
        public async Task<IEnumerable<IdentityResource>> FindIdentityResourcesByScopeNameAsync(IEnumerable<string> scopeNames)
        {
            var entities = await _queryService.GetQueryable<IdentityServer4.EntityFramework.Entities.IdentityResource>()
                .Include(x => x.UserClaims)
                .Include(x => x.Properties)
                .Where(o => scopeNames.Contains(o.Name))
                .ToListAsync();
            return entities.Select(o => o.ToModel());
        }
        public async Task<Resources> GetAllResourcesAsync()
        {
            var identity = _queryService.GetQueryable<IdentityServer4.EntityFramework.Entities.IdentityResource>()
                .Include(x => x.UserClaims)
                .Include(x => x.Properties);
            var apis = _queryService.GetQueryable<IdentityServer4.EntityFramework.Entities.ApiResource>()
                .Include(x => x.Secrets)
                .Include(x => x.Scopes)
                .Include(x => x.UserClaims)
                .Include(x => x.Properties)
                .AsNoTracking();
            var scopes = _queryService.GetQueryable<IdentityServer4.EntityFramework.Entities.ApiScope>()
                .Include(x => x.UserClaims)
                .Include(x => x.Properties)
                .AsNoTracking();
            var result = new Resources(
                (await identity.ToArrayAsync()).Select(o => o.ToModel()),
                (await apis.ToArrayAsync()).Select(o => o.ToModel()),
                (await scopes.ToArrayAsync()).Select(o => o.ToModel())
            );
            return result;
        }
    }
}
